﻿#include <QPainter>
#include "JZGLItem.h"
#include "JZGLScene.h"

//VertexData
VertexData::VertexData()
{
}

//JZGLItem
void JZGLItem::worldToLocal(const QVector<QVector3D>& world_list, QVector3D &pos, QVector<QVector3D> &local_list)
{
    QVector3D center;
    local_list = world_list;
    for (int i = 0; i < local_list.size(); i++)
        center += world_list[i];

    center /= world_list.size();
    for (int i = 0; i < local_list.size(); i++)
        local_list[i] -= center;

    pos = center;
}

JZGLItem::JZGLItem()
{
    m_type = GLItem_None;
    m_drawType = GLDraw_Mesh;
    m_scene = nullptr;
    m_parent = nullptr;
    m_visible = false;
    m_model.setToIdentity();
}

JZGLItem::~JZGLItem()
{
    qDeleteAll(m_childItems);
    m_childItems.clear();
}

void JZGLItem::updateBuffer()
{

}

void JZGLItem::paint(QPainter* painter)
{
}

int JZGLItem::type() const
{
    return m_type;
}

void JZGLItem::setParent(JZGLItem* parent)
{
    m_parent = parent;
}

JZGLItem* JZGLItem::parent()
{
    return m_parent;
}

QVector3D JZGLItem::position()
{
    return m_position;
}

void JZGLItem::setPosition(QVector3D pos)
{
    m_position = pos;
    update();
}

void JZGLItem::setDrawType(GLDrawType type)
{
    m_drawType = type;
    update();
}

GLDrawType JZGLItem::drawType()
{
    return m_drawType;
}

QList<JZGLItem*> JZGLItem::childItems() const
{
    return m_childItems;
}

void JZGLItem::addChild(JZGLItem* item)
{
    Q_ASSERT(!item->parent());
    item->setParent(this);
    item->setScene(m_scene);
    m_childItems.push_back(item);
    update();
}

void JZGLItem::removeChild(JZGLItem* item)
{
    m_childItems.removeAll(item);
    update();
}

void JZGLItem::update()
{
    /*
    我们时常听到这样的说法 /结论“先缩放，再旋转，最后位移”
    即叉乘顺序必须是 SRT （列右乘TRS）
    */
    if (m_parent)
        m_parent->update();
    else if(m_scene)
        m_scene->notifyItemChanged(this);
}

bool JZGLItem::isVisible() const
{
    return m_visible;
}

void JZGLItem::setVisible(bool flag)
{
    m_visible = flag;
}

JZGLScene* JZGLItem::scene()
{
    if (m_parent)
        return m_parent->scene();
    else
        return m_scene;
}

QMatrix4x4 JZGLItem::model() const
{
    return m_model;
}

void JZGLItem::setModel(QMatrix4x4 m)
{
    m_model = m;
    update();
}

void JZGLItem::resetModel()
{
    m_model.setToIdentity();
    update();
}

void JZGLItem::scale(float x, float y, float z)
{
    m_model.scale(x, y, z);
    update();
}

void JZGLItem::rotate(float angle, float x, float y, float z)
{
    m_model.rotate(angle, x, y, z);
    update();
}

void JZGLItem::translate(float x, float y, float z)
{
    m_model.translate(x, y, z);
    update();
}

void JZGLItem::setScene(JZGLScene* scene)
{
    m_scene = scene;
    for (int i = 0; i < m_childItems.size(); i++)
        m_childItems[i]->setScene(m_scene);
}

void JZGLItem::setColor(QColor c)
{
    for (int i = 0; i < m_points.size(); i++)
        m_points[i].color = c;
    update();
}

void JZGLItem::setVertexColor(int index, QColor c)
{
    m_points[index].color = c;
    update();
}

VertexData JZGLItem::vertex(int index)
{
    return m_points[index];
}

void JZGLItem::setVertex(int index, VertexData pt)
{
    m_points[index] = pt;
    update();
}

void JZGLItem::setVertexList(const QVector<VertexData>& points)
{
	m_points = points;
    update();
}

QVector<int> JZGLItem::meshIndexToLineIndex(const QVector<int>& index_list) //从三角形到线段
{
    QVector<int> line_index;
    for (int i = 0; i < index_list.size(); i+= 3)
    {
        line_index.push_back(index_list[i]);
        line_index.push_back(index_list[i + 1]);

        line_index.push_back(index_list[i + 1]);
        line_index.push_back(index_list[i + 2]);

        line_index.push_back(index_list[i + 2]);
        line_index.push_back(index_list[i]);
    }
    return line_index;
}

void JZGLItem::addLineVertex(const QVector<VertexData>& pt_list, const QVector<int>& index_list)
{
    Q_ASSERT(index_list.size() % 2 == 0);

    auto s = scene();
    s->addLineVertex(this, pt_list, index_list);
}

void JZGLItem::addMeshVertex(const QVector<VertexData>& pt_list, const QVector<int>& index_list)
{
    Q_ASSERT(index_list.size() % 3 == 0);

    auto s = scene();
    s->addMeshVertex(this, pt_list, index_list);
}

//GLLineItem
JZGLLineItem::JZGLLineItem()
{
    m_type = GLItem_Line;

    VertexData p1, p2;
    p1.pos = QVector3D(0, 0, 0);
    p2.pos = QVector3D(1, 0, 0);
    p1.color = Qt::white;
    p2.color = Qt::white;
    setLine(p1, p2);
}

void JZGLLineItem::setLine(VertexData p1, VertexData p2)
{
    setVertexList({ p1,p2 });
}


void JZGLLineItem::updateBuffer()
{
    Q_ASSERT(m_points.size() == 2);

    addLineVertex(m_points, { 0,1 });
}

//GLTriangleItem
JZGLTriangleItem::JZGLTriangleItem()
{
    m_type = GLItem_Triangle;

    QVector<VertexData> pt_list(3);
    pt_list[0].pos = QVector3D(0, 0, 0);
    pt_list[1].pos = QVector3D(1, 0, 0);
    pt_list[2].pos = QVector3D(1, 1, 0);
    pt_list[0].color = Qt::white;
    pt_list[1].color = Qt::white;
    pt_list[2].color = Qt::white;
    setVertexList(pt_list);
}

void JZGLTriangleItem::setTriangle(VertexData p1, VertexData p2, VertexData p3)
{
    setVertexList({ p1,p2,p3 });
}

void JZGLTriangleItem::updateBuffer()
{
	Q_ASSERT(m_points.size() == 3);
    if (m_drawType == GLDraw_Mesh)
        addMeshVertex(m_points, { 0,1,2});
    else
        addLineVertex(m_points, { 0,1, 1,2, 2,0 });
}


//JZGLRectItem
JZGLRectItem::JZGLRectItem()
{
    m_type = GLItem_Rect;
    setRect(1, 1, Qt::white);
}

void JZGLRectItem::setRect(float w, float h,QColor c)
{
    QVector<VertexData> pt_list(4);
    pt_list[0].pos = QVector3D(-w/2, h/2, 0);
    pt_list[1].pos = QVector3D(w/2, h/2, 0);
    pt_list[2].pos = QVector3D(w/2, -h/2, 0);
    pt_list[3].pos = QVector3D(-w/2, -h/2, 0);
    for (int i = 0; i < pt_list.size(); i++)
        pt_list[i].color = c;

    setVertexList(pt_list);
}

void JZGLRectItem::setRect(const QVector<VertexData>& vertex_list)
{
    Q_ASSERT(vertex_list.size() == 4);
    setVertexList(vertex_list);
}

void JZGLRectItem::updateBuffer()
{
	Q_ASSERT(m_points.size() == 4);

    if (m_drawType == GLDraw_Mesh)
        addMeshVertex(m_points, { 0,1,2, 0,2,3 });
    else
        addLineVertex(m_points, { 0,1,1,2,2,3,3,0 });
}

//JZGLBoxItem
JZGLBoxItem::JZGLBoxItem()
{
    m_type = GLItem_Box;
    setBox(1, 1, 1, Qt::white);
}

void JZGLBoxItem::setBox(float w, float h, float depth, QColor c)
{
    QVector<VertexData> pt_list(8);
    pt_list[0].pos = QVector3D(-w/2,-h/2, -depth/2);
    pt_list[1].pos = QVector3D(w/2, -h/2, -depth/2);
    pt_list[2].pos = QVector3D(w/2,  h/2, -depth/2);
    pt_list[3].pos = QVector3D(-w/2, h/2, -depth/2);    
 
    pt_list[4].pos = QVector3D(-w/2,-h/2, depth/2);
    pt_list[5].pos = QVector3D(w/2, -h/2, depth/2);
    pt_list[6].pos = QVector3D(w/2,  h/2, depth/2);
    pt_list[7].pos = QVector3D(-w/2, h/2, depth/2); 

    for (int i = 0; i < pt_list.size(); i++)
        pt_list[i].color = c;
    
    setBox(pt_list);
}

void JZGLBoxItem::setBox(const QVector<VertexData>& vertex_list)
{
    Q_ASSERT(vertex_list.size() == 8);    
    setVertexList(vertex_list);
}

void JZGLBoxItem::updateBuffer()
{
	Q_ASSERT(m_points.size() == 8);

    // 立方体的索引数据（36个索引，组成12个三角形面），保持不变
    QVector<int> boxIndices = {
        // 前面
        0, 1, 2,
        0, 2, 3,
        // 后面
        4, 5, 6,
        4, 6, 7,
        // 左面
        0, 4, 7,
        0, 7, 3,
        // 右面
        1, 5, 6,
        1, 6, 2,
        // 上面
        3, 2, 6,
        3, 6, 7,
        // 下面
        0, 1, 5,
        0, 5, 4
    };

    if (m_drawType == GLDraw_Mesh)
    {
        addMeshVertex(m_points,boxIndices);
    }
    else
    {
        QVector<int> lineIndices;
        for (int i = 0; i < boxIndices.size(); i += 6)
        {
            lineIndices.push_back(boxIndices[i]);
            lineIndices.push_back(boxIndices[i + 1]);

            lineIndices.push_back(boxIndices[i + 1]);
            lineIndices.push_back(boxIndices[i + 2]);

            lineIndices.push_back(boxIndices[i + 2]);
            lineIndices.push_back(boxIndices[i + 5]);

            lineIndices.push_back(boxIndices[i + 5]);
            lineIndices.push_back(boxIndices[i]);
        }

        addLineVertex(m_points, lineIndices);
    }
}

//JZGLTextItem
JZGLTextItem::JZGLTextItem()
{
    m_type = GLItem_Text;
    m_drawType = GLDraw_2D;
    m_color = Qt::white;
}

void JZGLTextItem::setColor(QColor c)
{
    m_color = c;
}

void JZGLTextItem::setText(QString text)
{
    m_text = text;
    update();
}

void JZGLTextItem::paint(QPainter* painter)
{
    painter->setPen(m_color);
    painter->drawText(0, 0, m_text);
}

//JZGLMeshItem
JZGLMeshItem::JZGLMeshItem()
{
    m_type = GLItem_Mesh;
}